/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 *(C) Copyright 2006 Marvell International Ltd.
 * All Rights Reserved
 */

/**  FILENAME:   xllp_gpio.c
**
**  PURPOSE:    contains XLLP GPIO primitives.
**
**  Validity Notes: Only valid for the processor codenamed "Monahans."
**
******************************************************************************/

#include "arch.h"
#include "xllp_gpio.h"
#include "xllp_i2c.h"

#define CONFIG_CPU_MONAHANS_LV

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)

/**************************
 * I2C API
 **************************/
// Write "bytesCount" data from "bytesBuf" to slave device "slaveAddr", Return: 0-success, non-0: error
extern int OS_I2CMasterWriteData(XLLP_UINT8_T slaveAddr, const XLLP_UINT8_T * bytesBuf, int bytesCount);

// Read "bufLen" data to "bytesBuf" to slave device "slaveAddr", Return: 0-success, non-0: error
extern int OS_I2CMasterReadData(XLLP_UINT8_T slaveAddr, XLLP_UINT8_T * bytesBuf, int bufLen);

typedef enum {
    XLLP_RESOURCE_I2C = 0,
    XLLP_RESOURCE_MFPR,          // MFP registers
    XLLP_RESOURCE_MFPR_RM,       // MFP resource manager
    XLLP_RESOURCE_ID_COUNT,
    XLLP_RESOURCE_CLK_EN
} XLLP_PROTECTED_RESOURCES_ID_T; // more IDs might be added

int OS_I2CMasterWriteData(XLLP_UINT8_T slaveAddr, const XLLP_UINT8_T * bytesBuf, int bytesCount)
{
    return XllpI2CWrite((P_XLLP_I2C_T)I2C_BASE, (P_XLLP_OST_T)OST_BASE, slaveAddr, bytesBuf, bytesCount, XLLP_TRUE);
}

int OS_I2CMasterReadData(XLLP_UINT8_T slaveAddr, XLLP_UINT8_T * bytesBuf, int bufLen)
{
    return XllpI2CRead((P_XLLP_I2C_T)I2C_BASE, (P_XLLP_OST_T)OST_BASE, slaveAddr, bytesBuf, bufLen, XLLP_TRUE);
}

XLLP_STATUS_T XllpLock(XLLP_PROTECTED_RESOURCES_ID_T Xllp_RegisterID);
XLLP_STATUS_T XllpUnlock(XLLP_PROTECTED_RESOURCES_ID_T Xllp_LockID);
/******************************************************************************
 * Function: XllpGpioExpanderRead
 *
 * Description: Read status register of GPIO expander.
 *
 * Input Parameters:
 *  expAddr - the GPIO expander I2C slave address
 *  reg - the status register
 *
 * Output Parameters:
 *  pval    - the value of the status register
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs.
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioExpanderRead( XLLP_UINT8_T expAddr,
 *              XLLP_UINT8_T reg,
 *              XLLP_UINT8_T *pval)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioExpanderRead( XLLP_UINT8_T expAddr,
            XLLP_UINT8_T reg,
            XLLP_UINT8_T *pval)
{
    XLLP_STATUS_T status;
    XLLP_UINT8_T buf[1];

    buf[0] = reg;
    XllpLock(XLLP_RESOURCE_I2C);
    status = OS_I2CMasterWriteData(expAddr, buf, 1);
        if (status != XLLP_STATUS_SUCCESS) {
            XllpUnlock(XLLP_RESOURCE_I2C);
            return status;
        }

        status = OS_I2CMasterReadData(expAddr, pval, 1);
        XllpUnlock(XLLP_RESOURCE_I2C);
        return status;
}

/******************************************************************************
 * Function: XllpGpioExpanderWrite
 *
 * Description: Write control register of GPIO expander.
 *
 * Input Parameters:
 *  expAddr - the GPIO expander I2C slave address
 *  reg - the control register
 *  val - the value written to the control register
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs.
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioExpanderWrite( XLLP_UINT8_T expAddr,
 *              XLLP_UINT8_T reg,
 *              XLLP_UINT8_T val)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioExpanderWrite(XLLP_UINT8_T expAddr,
        XLLP_UINT8_T reg,
        XLLP_UINT8_T val)
{
    XLLP_UINT8_T buf[2];
    XLLP_STATUS_T status;

    buf[0] = reg;
    buf[1] = val;

    XllpLock(XLLP_RESOURCE_I2C);
    status = OS_I2CMasterWriteData(expAddr, buf, 2);
    XllpUnlock(XLLP_RESOURCE_I2C);
    return status;
}
#endif

/******************************************************************************
 * Function: XllpGpioGetLevel
 *
 * Description: Reports the current level of the specified GPIO ID entity.
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *
 * Output Parameters:
 *  pLevel  - address of a variable to receive the level.
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs.
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioGetLevel( P_XLLP_GPIO_T pGPIO,
 *                 XLLP_UINT32_T gpioId,
 *                 XLLP_LEVEL_T* pLevel)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioGetLevel (P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_LEVEL_T* pLevel)
{
    XLLP_UINT32_T index, bit, value;
#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    XLLP_UINT8_T tmp;
#endif

#if defined(XLLP_DEBUG_PARAM_CHECK)
    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);
#endif// defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_GPIO_ID_END) {    // The pin is connect to GPIO expander
        if (gpioId > XLLP_EXP1_GPIO_HALF) { // from the second expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 1, &tmp);
            bit = (gpioId - XLLP_EXP1_GPIO_HALF) - 1;

            *pLevel = XLLP_LO;
            if (tmp & (0x1 << bit))
                *pLevel = XLLP_HI;

            return XLLP_STATUS_SUCCESS;
        } else if (gpioId > XLLP_EXP0_GPIO_END) { // from the second expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 0, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_END) - 1;

            *pLevel = XLLP_LO;
            if (tmp & (0x1 << bit))
                *pLevel = XLLP_HI;

            return XLLP_STATUS_SUCCESS;
        } else if (gpioId > XLLP_EXP0_GPIO_HALF) { // from the first expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 1, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_HALF) - 1;

            *pLevel = XLLP_LO;
            if (tmp & (0x1 << bit))
                *pLevel = XLLP_HI;

            return XLLP_STATUS_SUCCESS;
        } else if (gpioId > XLLP_GPIO_ID_END) { // from the first expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 0, &tmp);
            bit = (gpioId - XLLP_GPIO_ID_END) - 1;

            *pLevel = XLLP_LO;
            if (tmp & (0x1 << bit))
                *pLevel = XLLP_HI;

            return XLLP_STATUS_SUCCESS;
        }
    } else {        // Normal GPIO pin

#endif
    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    switch (index) {
        case 0:
            value = pGPIO->gplr0;
            break;
        case 1:
            value = pGPIO->gplr1;
            break;
        case 2:
            value = pGPIO->gplr2;
            break;
        case 3:
            value = pGPIO->gplr3;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return (XLLP_STATUS_WRONG_PARAMETER);
    }

    *pLevel = XLLP_LO;
    if (value & (0x1<<bit))
        *pLevel = XLLP_HI;

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    }
#endif
    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioSetOutputLevel
 *
 * Description: Sets the output level of the specified GPIO ID entity
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *  level   - the new output level.
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs or
 *      level is not in XLLP_LEVEL_T.
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioSetOutputLevel( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_LEVEL_T  level)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioSetOutputLevel (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_LEVEL_T level)
{
    XLLP_UINT32_T index, bit, value;
#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    XLLP_UINT8_T tmp;
#endif

#if defined(XLLP_DEBUG_PARAM_CHECK)

    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((level != XLLP_LO) && (level != XLLP_HI))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_GPIO_ID_END) {    // The pin is connect to GPIO expander
        if (gpioId > XLLP_EXP1_GPIO_HALF) { // from the second expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 3, &tmp);
            bit = (gpioId - XLLP_EXP1_GPIO_HALF) - 1;

#if 0
            if ((XLLP_LO == level) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_HI == level) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_LO == level)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            return XllpGpioExpanderWrite(XLLP_GPIO_EXP1_ADDR, 3, tmp);
        } else if (gpioId > XLLP_EXP0_GPIO_END) { // from the second expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 2, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_END) - 1;

#if 0
            if ((XLLP_LO == level) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_HI == level) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_LO == level)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            return XllpGpioExpanderWrite(XLLP_GPIO_EXP1_ADDR, 2, tmp);
        } else if (gpioId > XLLP_EXP0_GPIO_HALF) { // from the first expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 3, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_HALF) - 1;

#if 0
            if ((XLLP_LO == level) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_HI == level) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_LO == level)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            return XllpGpioExpanderWrite(XLLP_GPIO_EXP0_ADDR, 3, tmp);
        } else if (gpioId > XLLP_GPIO_ID_END) { // from the first expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 2, &tmp);
            bit = (gpioId - XLLP_GPIO_ID_END) - 1;

#if 0
            if ((XLLP_LO == level) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_HI == level) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_LO == level)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            return XllpGpioExpanderWrite(XLLP_GPIO_EXP0_ADDR, 2, tmp);
        }
    } else {        // Normal GPIO pin

#endif
    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    value = (0x1<<bit);
    switch (index) {
        case 0:
            if (level == XLLP_LO)
                pGPIO->gpcr0 = value;
            else
                pGPIO->gpsr0 = value;
            break;
        case 1:
            if (level == XLLP_LO)
                pGPIO->gpcr1 = value;
            else
                pGPIO->gpsr1 = value;
            break;
        case 2:
            if (level == XLLP_LO)
                pGPIO->gpcr2 = value;
            else
                pGPIO->gpsr2 = value;
            break;
        case 3:
            if (level == XLLP_LO)
                pGPIO->gpcr3 = value;
            else
                pGPIO->gpsr3 = value;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return(XLLP_STATUS_WRONG_PARAMETER);
    }
#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    }
#endif
    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioGetDirection
 *
 * Description: Reports the current direction configuration of the specified
 *  GPIO ID entity (typically a pin)
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *
 * Output Parameters:
 *  pDirection- address of a variable to receive the direction
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioGetDirection( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_GPIO_DIRECTION_T* pDirection)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioGetDirection (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_GPIO_DIRECTION_T * pDirection)
{
    XLLP_UINT32_T index, bit, value;
#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    XLLP_UINT8_T tmp;
#endif

#if defined(XLLP_DEBUG_PARAM_CHECK)
    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);
#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_GPIO_ID_END) {    // The pin is connect to GPIO expander
        if (gpioId > XLLP_EXP1_GPIO_HALF) { // from the second expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 7, &tmp);
            bit = (gpioId - XLLP_EXP1_GPIO_HALF) - 1;

            *pDirection = XLLP_GPIO_DIRECTION_OUT;
            if (tmp & (0x1<<bit))
                *pDirection = XLLP_GPIO_DIRECTION_IN;

            return XLLP_STATUS_SUCCESS;
        } else if (gpioId > XLLP_EXP0_GPIO_END) { // from the second expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 6, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_END) - 1;

            *pDirection = XLLP_GPIO_DIRECTION_OUT;
            if (tmp & (0x1<<bit))
                *pDirection = XLLP_GPIO_DIRECTION_IN;

            return XLLP_STATUS_SUCCESS;
        } else if (gpioId > XLLP_EXP0_GPIO_HALF) { // from the first expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 7, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_HALF) - 1;

            *pDirection = XLLP_GPIO_DIRECTION_OUT;
            if (tmp & (0x1<<bit))
                *pDirection = XLLP_GPIO_DIRECTION_IN;

            return XLLP_STATUS_SUCCESS;
        } else if (gpioId > XLLP_GPIO_ID_END) { // from the first expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 6, &tmp);
            bit = (gpioId - XLLP_GPIO_ID_END) - 1;

            *pDirection = XLLP_GPIO_DIRECTION_OUT;
            if (tmp & (0x1<<bit))
                *pDirection = XLLP_GPIO_DIRECTION_IN;

            return XLLP_STATUS_SUCCESS;
        }
    } else {        // Normal GPIO pin

#endif
    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    switch (index) {
        case 0:
            value = pGPIO->gpdr0;
            break;
        case 1:
            value = pGPIO->gpdr1;
            break;
        case 2:
            value = pGPIO->gpdr2;
            break;
        case 3:
            value = pGPIO->gpdr3;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return (XLLP_STATUS_WRONG_PARAMETER);
    }

    *pDirection = XLLP_GPIO_DIRECTION_IN;
    if (value & (0x1<<bit))
        *pDirection = XLLP_GPIO_DIRECTION_OUT;
#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    }
#endif
    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioSetDirection
 *
 * Description: Sets the direction of the specified GPIO ID entity.
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *  direction- the new direction
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioSetDirection( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_GPIO_DIRECTION_T direction)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioSetDirection (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_GPIO_DIRECTION_T direction)
{
    XLLP_UINT32_T index, bit, value;
#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    XLLP_UINT8_T tmp;
    XLLP_STATUS_T status = XLLP_STATUS_SUCCESS;
#endif

#if defined(XLLP_DEBUG_PARAM_CHECK)
    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((direction != XLLP_GPIO_DIRECTION_IN) &&
        (direction != XLLP_GPIO_DIRECTION_OUT))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_GPIO_ID_END) {    // The pin is connect to GPIO expander
        if (gpioId > XLLP_EXP1_GPIO_HALF) { // from the second expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 7, &tmp);
            bit = (gpioId - XLLP_EXP1_GPIO_HALF) - 1;

#if 0
            if ((XLLP_GPIO_DIRECTION_OUT == direction) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_GPIO_DIRECTION_IN == direction) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_GPIO_DIRECTION_OUT == direction)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            status = XllpGpioExpanderWrite(XLLP_GPIO_EXP1_ADDR, 7, tmp);
        } else if (gpioId > XLLP_EXP0_GPIO_END) { // from the second expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP1_ADDR, 6, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_END) - 1;

#if 0
            if ((XLLP_GPIO_DIRECTION_OUT == direction) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_GPIO_DIRECTION_IN == direction) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_GPIO_DIRECTION_OUT == direction)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            status = XllpGpioExpanderWrite(XLLP_GPIO_EXP1_ADDR, 6, tmp);
        } else if (gpioId > XLLP_EXP0_GPIO_HALF) { // from the first expander I1.0 ~ 1.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 7, &tmp);
            bit = (gpioId - XLLP_EXP0_GPIO_HALF) - 1;

#if 0
            if ((XLLP_GPIO_DIRECTION_OUT == direction) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_GPIO_DIRECTION_IN == direction) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_GPIO_DIRECTION_OUT == direction)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            status = XllpGpioExpanderWrite(XLLP_GPIO_EXP0_ADDR, 7, tmp);
        } else if (gpioId > XLLP_GPIO_ID_END) { // from the first expander I0.0 ~ 0.7
            XllpGpioExpanderRead(XLLP_GPIO_EXP0_ADDR, 6, &tmp);
            bit = (gpioId - XLLP_GPIO_ID_END) - 1;

#if 0
            if ((XLLP_GPIO_DIRECTION_OUT == direction) && (0 == (tmp & (0x01 << bit))))
                return XLLP_STATUS_SUCCESS;

            if ((XLLP_GPIO_DIRECTION_IN == direction) && (tmp & (0x01 << bit)))
                return XLLP_STATUS_SUCCESS;
#endif

            if (XLLP_GPIO_DIRECTION_OUT == direction)
                tmp &= ~(0x01 << bit);
            else
                tmp |= (0x01 << bit);

            status = XllpGpioExpanderWrite(XLLP_GPIO_EXP0_ADDR, 6, tmp);
        }
    } else {        // Normal GPIO pin

#endif
    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    value = (0x1<<bit);
    switch (index) {
        case 0:
            if (direction == XLLP_GPIO_DIRECTION_IN)
                pGPIO->gcdr0 = value;
            else
                pGPIO->gsdr0 = value;
            break;
        case 1:
            if (direction == XLLP_GPIO_DIRECTION_IN)
                pGPIO->gcdr1 = value;
            else
                pGPIO->gsdr1 = value;
            break;
        case 2:
            if (direction == XLLP_GPIO_DIRECTION_IN)
                pGPIO->gcdr2 = value;
            else
                pGPIO->gsdr2 = value;
            break;
        case 3:
            if (direction == XLLP_GPIO_DIRECTION_IN)
                pGPIO->gcdr3 = value;
            else
                pGPIO->gsdr3 = value;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return(XLLP_STATUS_WRONG_PARAMETER);
    }
#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
        status = XLLP_STATUS_SUCCESS;
    }
    return(status);
#else
    return(XLLP_STATUS_SUCCESS);
#endif
}

/******************************************************************************
 * Function: XllpGpioGetRisingEdgeDetectEnable
 *
 * Description: Reports whether or not Rising Edge Detection is enabled for
 *  the specified GPIO ID entity
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *
 * Output Parameters:
 *  pEnable - address of a variable to receive the Rising Edge Detect
 *        Enable
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioGetRisingEdgeDetectEnable( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_CONTROL_T* pEnable)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioGetRisingEdgeDetectEnable (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_CONTROL_T* pEnabled)
{
    XLLP_UINT32_T index, bit, value;

#if defined(XLLP_DEBUG_PARAM_CHECK)
    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_EXP0_GPIO_END)
        gpioId = 19;
    else if (gpioId > XLLP_GPIO_ID_END)
        gpioId = 18;
#endif

    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    switch (index) {
        case 0:
            value = pGPIO->grer0;
            break;
        case 1:
            value = pGPIO->grer1;
            break;
        case 2:
            value = pGPIO->grer2;
            break;
        case 3:
            value = pGPIO->grer3;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return (XLLP_STATUS_WRONG_PARAMETER);
    }

    *pEnabled = XLLP_OFF;
    if (value & (0x1<<bit))
        *pEnabled = XLLP_ON;

    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioSetRisingEdgeDetectEnable
 *
 * Description: Reports whether or not Rising Edge Detection is enabled for
 *  the specified GPIO ID entity
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *  enable  - the new setting for the Rising Edge Detect Enable
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioSetRisingEdgeDetectEnable( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_CONTROL_T enable)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioSetRisingEdgeDetectEnable  (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_CONTROL_T enable)
{
    XLLP_UINT32_T index, bit, value;

#if defined(XLLP_DEBUG_PARAM_CHECK)

    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((enable != XLLP_OFF) && (enable != XLLP_ON))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    /* If disable the edge detect, we can't just simply disable
     * GPIO18, 19 edge detect.
     *
     * So just return if caller want to disable the edge detect.
     * This is not correct behavior. So OS need do some special
     * work for this.
     */
    if ((gpioId > XLLP_GPIO_ID_END) && (XLLP_OFF == enable))
        return XLLP_STATUS_SUCCESS;
#endif

    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    value = (0x1<<bit);
    switch (index) {
        case 0:
            if (enable == XLLP_OFF)
                pGPIO->gcrer0 = value;
            else
                pGPIO->gsrer0 = value;
            break;
        case 1:
            if (enable == XLLP_OFF)
                pGPIO->gcrer1 = value;
            else
                pGPIO->gsrer1 = value;
            break;
        case 2:
            if (enable == XLLP_OFF)
                pGPIO->gcrer2 = value;
            else
                pGPIO->gsrer2 = value;
            break;
        case 3:
            if (enable == XLLP_OFF)
                pGPIO->gcrer3 = value;
            else
                pGPIO->gsrer3 = value;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return(XLLP_STATUS_WRONG_PARAMETER);
    }

    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioGetFallingEdgeDetectEnable
 *
 * Description: Reports whether or not Falling Edge Detection is enabled for
 *  the specified GPIO ID entity
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *
 * Output Parameters:
 *  pEnable - address of a variable to receive the Falling Edge Detect
 *        Enable
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioGetFallingEdgeDetectEnable( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_CONTROL_T* pEnable)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioGetFallingEdgeDetectEnable (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_CONTROL_T* pEnabled)
{
    XLLP_UINT32_T index, bit, value;

#if defined(XLLP_DEBUG_PARAM_CHECK)

    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_EXP0_GPIO_END)
        gpioId = 19;
    else if (gpioId > XLLP_GPIO_ID_END)
        gpioId = 18;
#endif

    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    switch (index) {
        case 0:
            value = pGPIO->gfer0;
            break;
        case 1:
            value = pGPIO->gfer1;
            break;
        case 2:
            value = pGPIO->gfer2;
            break;
        case 3:
            value = pGPIO->gfer3;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return (XLLP_STATUS_WRONG_PARAMETER);
    }

    *pEnabled = XLLP_OFF;
    if (value & (0x1<<bit))
        *pEnabled = XLLP_ON;

    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioSetFallingEdgeDetectEnable
 *
 * Description: Reports whether or not Falling Edge Detection is enabled for
 *  the specified GPIO ID entity
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *  enable  - the new setting for the Falling Edge Detect Enable
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioSetFallingEdgeDetectEnable( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_CONTROL_T enable)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioSetFallingEdgeDetectEnable (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_CONTROL_T enable)
{
    XLLP_UINT32_T index, bit, value;

#if defined(XLLP_DEBUG_PARAM_CHECK)

    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((enable != XLLP_OFF) && (enable != XLLP_ON))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    /* If disable the edge detect, we can't just simply disable
     * GPIO18, 19 edge detect.
     *
     * So just return if caller want to disable the edge detect.
     * This is not correct behavior. So OS need do some special
     * work for this.
     */
    if ((gpioId > XLLP_GPIO_ID_END) && (XLLP_OFF == enable))
        return XLLP_STATUS_SUCCESS;
#endif

    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    value = (0x1<<bit);
    switch (index) {
        case 0:
            if (enable == XLLP_OFF)
                pGPIO->gcfer0 = value;
            else
                pGPIO->gsfer0 = value;
            break;
        case 1:
            if (enable == XLLP_OFF)
                pGPIO->gcfer1 = value;
            else
                pGPIO->gsfer1 = value;
            break;
        case 2:
            if (enable == XLLP_OFF)
                pGPIO->gcfer2 = value;
            else
                pGPIO->gsfer2 = value;
            break;
        case 3:
            if (enable == XLLP_OFF)
                pGPIO->gcfer3 = value;
            else
                pGPIO->gsfer3 = value;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return(XLLP_STATUS_WRONG_PARAMETER);
    }

    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioGetEdgeDetectStatus
 *
 * Description: Reports whether or not an uncleared edge detection is
 *  registered for the specified GPIO ID entity
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *
 * Output Parameters:
 *  pDetectStatus: address of a variable to receive the detection state
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioGetEdgeDetectStatus( P_XLLP_GPIO_T pGPIO,
 *                  XLLP_UINT32_T gpioId,
 *                  XLLP_UINT32_T* pDetectStatus)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioGetEdgeDetectStatus (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId,
                                XLLP_UINT32_T* pDetectStatus)
{
    XLLP_UINT32_T index, bit, value;

#if defined(XLLP_DEBUG_PARAM_CHECK)

    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_EXP0_GPIO_END)
        gpioId = 19;
    else if (gpioId > XLLP_GPIO_ID_END)
        gpioId = 18;
#endif

    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    switch (index) {
        case 0:
            value = pGPIO->gedr0;
            break;
        case 1:
            value = pGPIO->gedr1;
            break;
        case 2:
            value = pGPIO->gedr2;
            break;
        case 3:
            value = pGPIO->gedr3;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return (XLLP_STATUS_WRONG_PARAMETER);
    }

    *pDetectStatus = 0;
    if (value & (0x1<<bit))
        *pDetectStatus = 1;

    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioGetEdgeDetectStatus
 *
 * Description: Clear any existing registered edge detection for the specified
 *  GPIO ID.
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  gpioId  - The ID of the GPIO whose level is being reported. Range is
 *        0..XLLP_GPIO_ID_MAX. Excludes the reserved GPIO IDs
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioClearEdgeDetectStatus( P_XLLP_GPIO_T pGPIO,
 *                      XLLP_UINT32_T gpioId)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioClearEdgeDetectStatus (
                                P_XLLP_GPIO_T pGPIO,
                                XLLP_UINT32_T gpioId)
{
    XLLP_UINT32_T index, bit, value;

#if defined(XLLP_DEBUG_PARAM_CHECK)

    if (!pGPIO)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if (gpioId > XLLP_GPIO_ID_MAX)
        return(XLLP_STATUS_WRONG_PARAMETER);

    if ((gpioId == XLLP_GPIO_ID_INVALID_56) ||
        (gpioId == XLLP_GPIO_ID_INVALID_59) ||
        (gpioId == XLLP_GPIO_ID_INVALID_60) ||
        (gpioId == XLLP_GPIO_ID_INVALID_61) ||
        (gpioId == XLLP_GPIO_ID_INVALID_62))
        return(XLLP_STATUS_WRONG_PARAMETER);

#endif // defined(XLLP_DEBUG_PARAM_CHECK)

#if defined(CONFIG_CPU_MONAHANS_PL) || defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
    if (gpioId > XLLP_EXP0_GPIO_END)
        gpioId = 19;
    else if (gpioId > XLLP_GPIO_ID_END)
        gpioId = 18;
#endif

    index = (gpioId & ~0x1f)>>5;
    bit = (gpioId & 0x1f);
    value = (0x1<<bit);
    switch (index) {
        case 0:
            pGPIO->gedr0 = value;
            break;
        case 1:
            pGPIO->gedr1 = value;
            break;
        case 2:
            pGPIO->gedr2 = value;
            break;
        case 3:
            pGPIO->gedr3 = value;
            break;
        default:
#if defined(XLLP_DEBUG)
            xllp_bug();
#endif
            return(XLLP_STATUS_WRONG_PARAMETER);
    }

    return(XLLP_STATUS_SUCCESS);
}

/******************************************************************************
 * Function: XllpGpioSave
 *
 * Description: Save the GPIO setting
 * Notes:   This function doesn't consider saving the context of GPIO expander
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  pSaveContext    - Place of saving GPIO settings
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioSave (
 *                            P_XLLP_GPIO_T pGPIO,
 *                            P_XLLP_GPIO_T pSaveContext)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioSave (
                            P_XLLP_GPIO_T pGPIO,
                            P_XLLP_GPIO_T pSaveContext)
{
    /* save directions*/
    pSaveContext->gpdr0 = pGPIO->gpdr0;
    pSaveContext->gpdr1 = pGPIO->gpdr1;
    pSaveContext->gpdr2 = pGPIO->gpdr2;
    pSaveContext->gpdr3 = pGPIO->gpdr3;

    /* save output levels */
    pSaveContext->gplr0 = pGPIO->gplr0;
    pSaveContext->gplr1 = pGPIO->gplr1;
    pSaveContext->gplr2 = pGPIO->gplr2;
    pSaveContext->gplr3 = pGPIO->gplr3;

    /* Save rising edge detect enabled gpio pins */
    pSaveContext->grer0 = pGPIO->grer0;
    pSaveContext->grer1 = pGPIO->grer1;
    pSaveContext->grer2 = pGPIO->grer2;
    pSaveContext->grer3 = pGPIO->grer3;

    /* Save falling edge detect enabled gpio pins */
    pSaveContext->gfer0 = pGPIO->gfer0;
    pSaveContext->gfer1 = pGPIO->gfer1;
    pSaveContext->gfer2 = pGPIO->gfer2;
    pSaveContext->gfer3 = pGPIO->gfer3;

    return XLLP_STATUS_SUCCESS;
}

/******************************************************************************
 * Function: XllpGpioRestore
 *
 * Description: restore the GPIO setting
 * Notes:   This function doesn't consider restoring the context of GPIO expander
 *
 * Input Parameters:
 *  pGPIO   - a pointer to the GPIO register set
 *  pSaveContext    - Place of saving GPIO settings
 *
 * Returns:
 *  XLLP_STATUS_SUCCESS     - All parameters were valid.
 *  XLLP_STATUS_WRONG_PARAMETER - Null pointer received or gpioId
 *      is either out of range or one of the reserved GPIO IDs
 *
 * Global effects:
 *
 * Assumptions:
 *
 * Calls:
 *
 * Called by:
 *
 * Prototype:
 * XLLP_STATUS_T XllpGpioRestore (
 *                            P_XLLP_GPIO_T pGPIO,
 *                            P_XLLP_GPIO_T pSaveContext)
 ******************************************************************************/
XLLP_STATUS_T XllpGpioRestore(
                            P_XLLP_GPIO_T pGPIO,
                            P_XLLP_GPIO_T pSaveContext)
{
    /* restore output directions*/
    pGPIO->gsdr0 = pSaveContext->gpdr0;
    pGPIO->gsdr1 = pSaveContext->gpdr1;
    pGPIO->gsdr2 = pSaveContext->gpdr2;
    pGPIO->gsdr3 = pSaveContext->gpdr3;

    /* restore input directions*/
    pGPIO->gcdr0 = ~pSaveContext->gpdr0;
    pGPIO->gcdr1 = ~pSaveContext->gpdr1;
    pGPIO->gcdr2 = ~pSaveContext->gpdr2;
    pGPIO->gcdr3 = ~pSaveContext->gpdr3;

    /* restore output high levels */
    pGPIO->gpsr0 = pSaveContext->gplr0;
    pGPIO->gpsr1 = pSaveContext->gplr1;
    pGPIO->gpsr2 = pSaveContext->gplr2;
    pGPIO->gpsr3 = pSaveContext->gplr3;

    /* restore output low levels */
    pGPIO->gpcr0 = ~pSaveContext->gplr0;
    pGPIO->gpcr1 = ~pSaveContext->gplr1;
    pGPIO->gpcr2 = ~pSaveContext->gplr2;
    pGPIO->gpcr3 = ~pSaveContext->gplr3;

    /* restore rising edge detect enabled gpio pins */
    pGPIO->gsrer0 = pSaveContext->grer0;
    pGPIO->gsrer1 = pSaveContext->grer1;
    pGPIO->gsrer2 = pSaveContext->grer2;
    pGPIO->gsrer3 = pSaveContext->grer3;

    /* restore rising edge detect disabled gpio pins */
    pGPIO->gcrer0 = ~pSaveContext->grer0;
    pGPIO->gcrer1 = ~pSaveContext->grer1;
    pGPIO->gcrer2 = ~pSaveContext->grer2;
    pGPIO->gcrer3 = ~pSaveContext->grer3;

    /* restore falling edge detect enabled gpio pins */
    pGPIO->gsfer0 = pSaveContext->gfer0;
   pGPIO->gsfer1 = pSaveContext->gfer1;
    pGPIO->gsfer2 = pSaveContext->gfer2;
    pGPIO->gsfer3 = pSaveContext->gfer3;

    /* restore falling edge detect disabled gpio pins */
    pGPIO->gcfer0 = ~pSaveContext->gfer0;
    pGPIO->gcfer1 = ~pSaveContext->gfer1;
    pGPIO->gcfer2 = ~pSaveContext->gfer2;
    pGPIO->gcfer3 = ~pSaveContext->gfer3;

    return XLLP_STATUS_SUCCESS;
}

#define XLLP_MAX7320_ADDRESS    0x50

XLLP_STATUS_T xllp_max7320_write(XLLP_UINT8_T reg, XLLP_UINT8_T val)
{
    XLLP_UINT8_T buffer[2];
    int status;
    buffer[0] = reg;
    buffer[1] = val;

    XllpLock(XLLP_RESOURCE_I2C);
    status = OS_I2CMasterWriteData(XLLP_MAX7320_ADDRESS, buffer, 2);
    XllpUnlock(XLLP_RESOURCE_I2C);
    return status;

}

XLLP_STATUS_T xllp_max7320_read(XLLP_UINT8_T reg, XLLP_UINT8_T *pval)
{
    XLLP_UINT8_T buffer[1];
    int status;
    buffer[0] = reg;

    XllpLock(XLLP_RESOURCE_I2C);
    status = OS_I2CMasterReadData(XLLP_MAX7320_ADDRESS, buffer, 1);
    *pval = buffer[0];
    XllpUnlock(XLLP_RESOURCE_I2C);
    return status;
}

